package com.miwzn.base;

import com.miwzn.boot.component.config.shiro.ShiroUser;
import com.miwzn.comm.constant.MyConstant;
import com.miwzn.comm.utils.CommUtil;
import com.miwzn.comm.utils.Page;
import com.miwzn.comm.utils.PageUtis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Auther: wzn
 * @Date: 2018/6/27 10:37
 * @Description:
 */
public abstract class AbstractBase<T, D extends BaseEntity, Q extends QueryEntity> {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    protected Class<T> tClass;    // 当前泛型真实类型的Class
    protected Class<D> dClass;    // 当前泛型真实类型的Class
    protected Class<Q> qClass;    // 当前泛型真实类型的Class

    public AbstractBase() {
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
        tClass = (Class<T>) pt.getActualTypeArguments()[0];
        dClass = (Class<D>) pt.getActualTypeArguments()[1];
        qClass = (Class<Q>) pt.getActualTypeArguments()[2];
    }

    /**
     * 反射设置字段值 T
     *
     * @param fieldName
     * @param fiedValue
     * @param record
     */
    void setFieldByT(String fieldName, Object fiedValue, T record) {
        try {
            Field field = this.tClass.getDeclaredField(fieldName);

            field.setAccessible(true);
            Object value = field.get(record);
            if (value == null && fiedValue != null) {
                field.set(record, fiedValue);
            }
            field.setAccessible(false);
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage(), e);
        } catch (NoSuchFieldException e) {
            logger.error(e.getMessage(), e);
        }
    }


    /**
     * 反射设置字段值 Q
     *
     * @param fieldName
     * @param fiedValue
     * @param record
     */
    void setFieldByQ(String fieldName, Object fiedValue, Q record) {
        try {
            Field field = this.qClass.getSuperclass().getDeclaredField(fieldName);

            field.setAccessible(true);
            Object value = field.get(record);
            if (value == null && fiedValue != null) {
                field.set(record, fiedValue);
            }
            field.setAccessible(false);
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage(), e);
        } catch (NoSuchFieldException e) {
            logger.error(e.getMessage(), e);
        }
    }


    /**
     * @param p
     * @param list
     *
     * @return
     */
    Page wrapTPage(com.github.pagehelper.Page p, List<T> list) {
        return wrapPage(p, list);
    }

    /**
     * @param p
     * @param list
     *
     * @return
     */
    Page wrapDPage(com.github.pagehelper.Page p, List<T> list) {
        List<D> ds = wrapDs(list);
        return wrapPage(p, ds);
    }

    /**
     * 包装分页数据
     *
     * @param p
     * @param list
     *
     * @return
     */
  public  Page wrapPage(com.github.pagehelper.Page p, List<?> list) {
        if (p == null) {
            Page page = new Page(list, list.size(), list.size(), 1, false);
            if (PageUtis.isOrderBy()) {
                page.setOrderByEnabled(true);
                page.setOrderBy(PageUtis.getPageFromThreadLocal().getOrderBy());
            }
            return page;
        } else {
            Page page = PageUtis.getPageFromThreadLocal();
            page.setCurrPage(p.getPageNum());
            page.setPageSize(p.getPageSize());
            page.setTotalPage(p.getPages());
            page.setTotalCount(p.getTotal());
            page.setList(list);
            return page;
        }
    }


    /**
     * 包装DTO
     *
     * @param t
     *
     * @return
     */
  public   D wrapD(T t) {
        D d = null;
        try {
            d = dClass.newInstance();
            BeanUtils.copyProperties(t, d);
        } catch (InstantiationException e) {
            logger.error(e.getMessage(), e);
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage(), e);
        }
        return d;
    }


    /**
     * 包装T
     *
     * @param d
     *
     * @return
     */
   public T wrapT(D d) {
        T t = null;
        try {
            t = tClass.newInstance();
            BeanUtils.copyProperties(d, t);
        } catch (InstantiationException e) {
            logger.error(e.getMessage(), e);
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage(), e);
        }
        return t;
    }


    /**
     * 包装DTO
     *
     * @param ts
     *
     * @return
     */
   public List<D> wrapDs(List<T> ts) {
        List<D> ds = new ArrayList<>();
        if (ts != null && ts.size() > 0) {
            for (T t : ts) {
                ds.add(wrapD(t));
            }
        }
        return ds;
    }

    /**
     * 插入或更新前处理时间创建人更新人删除标记
     *
     * @param record
     * @param opt
     */
    void insertOrUpdatePre(T record, String opt) {
        ShiroUser loginUser = null;
        try {
            loginUser = CommUtil.getLoginUser();
        } catch (Exception e) {
            e.printStackTrace();
        }
        String userId = loginUser != null ? loginUser.getId() : MyConstant.SUPER_ADMIN_ID;
        if ("insert".equals(opt)) {
            setFieldByT("createAt", userId, record);
            setFieldByT("createTime", new Date(), record);
            setFieldByT("delFlag", MyConstant.FLAG_N, record);
        }
        if ("update".equals(opt) || "insert".equals(opt)) {
            setFieldByT("updateAt", userId, record);
            setFieldByT("updateTime", new Date(), record);
        }
    }

    /**
     * 插入或更新前处理时间创建人更新人删除标记
     *
     * @param records
     * @param opt
     */
    void insertOrUpdatePre(List<T> records, String opt) {
        if (records == null || records.size() == 0) return;
        ShiroUser loginUser = null;
        try {
            loginUser = CommUtil.getLoginUser();
        } catch (Exception e) {
            e.printStackTrace();
        }
        String userId = loginUser != null ? loginUser.getId() : MyConstant.SUPER_ADMIN_ID;
        for (T record : records) {
            if ("insert".equals(opt)) {
                setFieldByT("createAt", userId, record);
                setFieldByT("createTime", new Date(), record);
                setFieldByT("delFlag", MyConstant.FLAG_N, record);
            }
            if ("update".equals(opt) || "insert".equals(opt)) {
                setFieldByT("updateAt", userId, record);
                setFieldByT("updateTime", new Date(), record);
            }
        }
    }

}
